package com.lipaluma.field.validator.impl.collections;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.List;

import com.lipaluma.annotations.validations.ValidateCollection;
import com.lipaluma.context.Context;
import com.lipaluma.exceptions.CsvParserProcessException;
import com.lipaluma.field.validator.ValidationError;
import com.lipaluma.field.validator.Validator;
import com.lipaluma.field.validator.strategies.LengthStrategy;
import com.lipaluma.xml.validator.XmlLengthValidator;
import com.lipaluma.xml.validator.XmlValidator;

public class CollectionSizeValidator implements Validator {

	private int threshold;
	private LengthStrategy strategy;
	
	public CollectionSizeValidator() {}
	public CollectionSizeValidator(int threshold) {
		this(threshold, LengthStrategy.EQUALS);
	}
	public CollectionSizeValidator(int threshold, LengthStrategy strategy) {
		this.threshold = threshold;
		this.strategy = strategy;
	}
	
	@Override
	public boolean init(Context context, Field field) {
		ValidateCollection annotationValidate = field.getAnnotation(ValidateCollection.class);
		if(annotationValidate != null && annotationValidate.length() >= 0) {
			this.threshold = annotationValidate.length();
			this.strategy = annotationValidate.lengthStrategy();
			return true;
		}
		return false;
	}

	@Override
	public boolean init(Context context, Field field, XmlValidator xmlValidator) {
		XmlLengthValidator validator = (XmlLengthValidator) xmlValidator;
		this.threshold = validator.getValue();
		this.strategy = validator.getLengthStrategy() != null ? validator.getLengthStrategy() : LengthStrategy.EQUALS;
		return true;
	}

	@Override
	public boolean validate(Object value, List<ValidationError> errors) {
		if(value.getClass().isArray()) {
			int size = Array.getLength(value);
			if(!strategy.validate(this.threshold, size)) {
				errors.add(new ValidationError("The size of "+value+" is not respecting strategy "+strategy+" with threshold "+threshold));
				return false;
			}
			return true;
		} else if(Collection.class.isAssignableFrom(value.getClass())) {
			int size = ((Collection<?>)value).size();
			if(!strategy.validate(this.threshold, size)) {
				errors.add(new ValidationError("The size of "+value+" is not respecting strategy "+strategy+" with threshold "+threshold));
				return false;
			}
			return true;
		} else
			throw new CsvParserProcessException("For the NotEmpty validation, the value must be an array or a Collection. But it was "+value.getClass());
	}


}
